package com.zeus.core.config.data;

import com.zeus.common.constants.ZeusConfigConstant;
import com.zeus.common.log.ZeusLoggerConfig;
import com.zeus.core.config.listener.ZeusAutoUpdateConfig;
import com.zeus.core.config.spring.ZeusApplicationContextHelper;
import lombok.Getter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.Environment;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;

/**
 * 宙斯上下文
 *
 * @author f1ybear_wang  2022/2/22 10:18 下午
 */
public abstract class AbstractZeusConfig implements ZeusConfig {
    private final static Logger log = LoggerFactory.getLogger(AbstractZeusConfig.class);

    /**
     * 配置监听器
     */
    @Getter
    protected Set<Listener> listeners = new HashSet<>();

    /**
     * 是否已经初始化
     */
    protected volatile boolean inited;

    /**
     * 报警配置信息
     */
    protected ZeusConfig.ConfigData alarmConfig;

    /**
     * 配置源变化监听器，用于监听来自Apollo等配置源的变化
     */
    protected List<ZeusAutoUpdateConfig> zeusAutoUpdateConfigList = new ArrayList<>();

    public AbstractZeusConfig() {
        if (log.isInfoEnabled() && ZeusLoggerConfig.needEnableLogger()) {
            log.info(">>> 宙斯准备加载配置");
        }
        // 初始化
        init();
    }

    abstract void init();

    abstract void doRefresh();

    @Override
    public void addListener(Listener listener) {
        if (listener != null) {
            listeners.add(listener);
        }

        // 刷新配置
        doRefresh();
    }

    @Override
    public void refresh() {
        try {
            Thread.sleep(5_000L);
        } catch (InterruptedException ignored) {
        }
        doRefresh();
    }

    @Override
    public ConfigData getConfigData() {
        if (this.alarmConfig != null) {
            return this.alarmConfig;
        }
        // 初始化
        init();
        if (this.alarmConfig != null) {
            return this.alarmConfig;
        }
        if (log.isWarnEnabled() && ZeusLoggerConfig.needEnableLogger()) {
            log.warn("### 获取宙斯配置数据失败，初始化后仍获取不到");
        }
        return null;
    }

    /**
     * 发送配置改变通知
     * 
     * @author f1ybear_wang  2022/5/7 14:21
     */
    protected void sendConfigChangeEvent() {
        if (this.alarmConfig == null) {
            return;
        }
        if (log.isWarnEnabled() && ZeusLoggerConfig.needEnableLogger()) {
            log.warn("### 宙斯准备更新配置");
        }
        for (Listener listener : listeners) {
            if (listener != null) {
                listener.updateConfig(this.alarmConfig);
            }
        }
    }

    /**
     * 获取配置源
     *
     * @param   key 键
     * @return 值
     */
    protected String getProperty(String key) {
        return getProperty(key, null);
    }

    /**
     * 获取配置源
     *
     * @param   key 键
     * @param   defaultValue 默认值
     * @return 值
     */
    protected String getProperty(String key, String defaultValue) {
        if (key == null) {
            return null;
        }
        // 读取配置文件 zeus.properties
        if (StaticConfig.getZeusProperties() != null && !StaticConfig.getMustUseEnvironmentKeyList().contains(key)) {
            return StaticConfig.getZeusProperties().getProperty(key, defaultValue);
        }

        // 读取Environment，会尝试读取2次
        for (int i = 0; i < 2; i++) {
            Environment environment = ZeusApplicationContextHelper.popBean(Environment.class);
            if (environment != null) {
                return environment.getProperty(key, defaultValue);
            }
        }
        return null;
    }

    /**
     * 校验配置源
     * 
     * @return true:配置源存在 false:配置源不存在
     */
    protected boolean checkConfigSource() {
        if (StaticConfig.getZeusProperties() != null) {
            return true;
        }
        Environment environment = ZeusApplicationContextHelper.popBean(Environment.class);
        if (environment != null && environment.getProperty(ZeusConfigConstant.Key.Base.MONITOR_ENABLED) != null) {
            return true;
        }
        return false;
    }

    private static class StaticConfig {
        /**
         * 宙斯配置文件
         */
        @Getter
        private static Properties zeusProperties;

        /**
         * 宙斯配置文件路径
         */
        private static final String PROPERTIES_FILE = "/zeus-config.properties";

        /**
         * 必须使用Environment读取配置的key集合
         */
        @Getter
        private static List<String> mustUseEnvironmentKeyList = new ArrayList<>();

        // 初始化宙斯配置文件
        static {
            mustUseEnvironmentKeyList.add(ZeusConfigConstant.Key.Base.APPLICATION_NAME);
            mustUseEnvironmentKeyList.add(ZeusConfigConstant.Key.Base.SPRING_PROFILES_ACTIVE);

            InputStream in = null;
            try {
                in = Thread.currentThread().getContextClassLoader().getResourceAsStream(PROPERTIES_FILE);

                if (in == null) {
                    in = ZeusConfig.class.getResourceAsStream(PROPERTIES_FILE);
                }
                if (in != null) {
                    Properties prop = new Properties();

                    prop.load(new InputStreamReader(in, StandardCharsets.UTF_8));

                    // 必须配置此项，否则配置无效
                    String enabled = prop.getProperty(ZeusConfigConstant.Key.Base.MONITOR_ENABLED);
                    if (enabled != null) {
                        zeusProperties = prop;
                        if (log.isInfoEnabled()) {
                            log.info(">>> 宙斯配置数据源读取本地zeus-config.properties文件内容完成");
                        }
                    }
                }
            } catch (Exception ignored) {
            } finally {
                if (in != null) {
                    try {
                        in.close();
                    } catch (Exception ignored) {
                    }
                }
            }
        }
    }

}
